
// ================================================================================================
// -*- C++ -*-
// File: Ant.hpp
// Author: Guilherme R. Lampert
// Created on: 17/09/13
// Brief: Represents one of our ants.
// ================================================================================================

#ifndef __ANT_HPP__
#define __ANT_HPP__

class WorldState;

// A goal is a location in the world
// map, withing the ant's field of view.
// As long as the expected contents of the goal
// match the world state, the ant will move towards it.
struct Goal {
	Location mapLocation;
	int expectedContents;
	bool active;
};

// Each ant we create is represent by an instance of this class:
class Ant {

public:

	// Distance in tiles an ant can "see".
	// This is the integer part of the square root
	// of the startup parameter 'viewradius2'
	static int viewDistance;

public:

	// Define a new ant:
	Ant(int x, int y, WorldState * ws);

	// Get current ant location in the tile map.
	inline const Location & GetLocation() const
	{
		return (location);
	}

	// Test current ant location in the map.
	inline bool IsAt(int x, int y) const
	{
		return ((this->location.x == x) &&
		        (this->location.y == y));
	}

	// Two ant are considered equal if they occupy the same map cell.
	inline bool operator == (const Ant & other) const
	{
		return ((this->location.x == other.location.x) &&
		        (this->location.y == other.location.y));
	}

	// Test if this ant has an active goal.
	inline bool HasGoal() const
	{
		return (goal.active);
	}

	// Set a new active goal, overwriting previous.
	inline void SetGoal(int x, int y, MapCellContents expectedContents)
	{
		goal.mapLocation.x    = x;
		goal.mapLocation.y    = y;
		goal.expectedContents = expectedContents;
		goal.active           = true;
	}

	// Set a new active goal, overwriting previous.
	inline void SetGoal(const std::list<int> & pathToGoal, MapCellContents expectedContents)
	{
		// goal location is irrelevant. We will follow whatever is in the path.
		goal.mapLocation.x    = -1;
		goal.mapLocation.y    = -1;
		goal.expectedContents = expectedContents;
		goal.active           = true;

		// Follow complex path:
		path = pathToGoal;
		path.pop_front(); // First one is the current location. We can discard it.
	}

	// Get current goal.
	inline const Goal & GetGoal() const
	{
		return (goal);
	}

	// Test if it is time to do a complex search or we should just do a cheap random move.
	bool ShouldDoComplexSearch() const;

	// See if there is a strait line from the current position
	// to any cell that has its contents equal to a member of 'lookFor'.
	// If the return is 'true', then 'loc' contains the 2D location
	// of the node that had the wanted contents. 'found' is what was found there.
	bool HasLineOfSightTo(const MapCellContents lookFor[], int num, Location & loc, MapCellContents & found) const;

	// Moves another step towards the active goal.
	// Once it is reached, the goal is set to inactive.
	void MoveToGoal();

	// Performs a move in a random direction.
	void RandomMove();

	// Dumps this ant's state to the debug log.
	void DebugDump() const;

private:

	// Actually moves the ant. Used by MoveToGoal() and RandomMove().
	bool DoMove(Location currentLocation, Location newLocation, int direction);

	// Pointer to the world state that created this ant.
	WorldState * state;

	// Every now and then we do a complex search.
	// This way we can balance CPU usage and hopefully avoid timing out.
	mutable int timeForComplexSeach;

	// When in random walk mode, use these to keep track:
	int timeForNewRand;
	int currentRandDir;

	// Current location of this ant in the world map.
	Location location;

	// Goal this ant is moving to, if active.
	Goal goal;

	// Path of graph nodes used for more complex movements that involve turns.
	std::list<int> path;
};

#endif // __ANT_HPP__
